package com.sc.datacollect.netty.server;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sc.datacollect.imple.AirFactor;
import com.sc.datacollect.imple.IProtocol;
import com.sc.datacollect.main.MainCollect;
import com.sc.datacollect.netty.model.AirBaseSrc_Ety;
import com.sc.datacollect.netty.model.IValue;
import com.sc.datacollect.netty.model.ValueType;
import com.sc.datacollect.util.CommonConfig;
import com.sc.datacollect.util.MongoDb;
import com.sc.datacollect.util.UnifiedCodePo;
import com.sc.datacollect.util.UnifiedcodeUtil;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class Data212TransferServerHandler extends ChannelInboundHandlerAdapter {

	private Logger log = Logger.getLogger(Data212TransferServerHandler.class);

	private MongoDb mongodb = MainCollect.mongodb;
	private IProtocol iprotocol;

	private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try {
			byte[] buffer = (byte[]) msg;

			if (buffer == null || buffer.length == 0) {
				ctx.writeAndFlush(false);
			}
			
			String text = null;
			String string = new String(buffer, "GB2312");
//			log.info("六因子::::::" + string);
			// 数据为空
			if (buffer == null || buffer.length - 2 - 4 <= 0 || string == null || string.equals("") || !string.contains("####") || !string.contains("@@@")) {
				return;
			}
			
			ValueType valueType = convertHeader(string.substring(0, 4));
			if (valueType == ValueType.Unknown) {
//				log.info("不识别的数据类型" + new String(buffer));
				return;
			}
			String body = string.substring(0, string.indexOf("####"));
			
			if (body == null) {
				text = String.format("@@@" + sdf.format(new Date()) + "tek");
				ctx.writeAndFlush(encode(text));
				return;
			}
			log.info("六因子::::::" + valueType.getName() + "===" + body);
			String header = body.substring(0, string.indexOf("@@@"));
			if (valueType != ValueType.QC && valueType != ValueType.QCTaskList) {
				List<IValue> list = decode(body, valueType);
				
				if (list.size() > 0) {
					JSONObject data = new JSONObject();
					data.put("createTime", sdf.format(new Date()));
					String siteCode = list.get(0).getStationCode().substring(0, 3);
					String deviceCode = list.get(0).getStationCode().substring(3, 6);
					
					siteCode = CommonConfig.siteConfig.getProperty(siteCode);
					deviceCode = CommonConfig.deviceConfig.getProperty(deviceCode);
					
					data.put("siteCode", siteCode);
					data.put("deviceCode", deviceCode);
					data.put("monitorTime", sdf.format(list.get(0).getTimePoint()));
					data.put("ValueType", list.get(0).getType());
					
					JSONObject trans = (JSONObject) data.clone();
					JSONArray objv = new JSONArray();
					JSONArray transv = new JSONArray();
					JSONObject obj = new JSONObject();
					JSONObject transobj = new JSONObject();
					String pollutant = "";
					
					List<UnifiedCodePo> pos = new LinkedList<UnifiedCodePo>();
					UnifiedCodePo po = null;
					for (IValue iValue : list) {
						po = new UnifiedCodePo();
						po.setInCode(iValue.getPollutantCode());
						po.setCatalogCode("ITP_AIR");
						pos.add(po);
					}
					// 调用编码转换
					pos = UnifiedcodeUtil.convert(pos);
					
					for (IValue iValue : list) {
						obj = new JSONObject();
						
						pollutant = iValue.getPollutantCode();
						
						String myCode = UnifiedcodeUtil.getMyCode(pos, pollutant);
//						String myCode = pollutant;
						
						obj.put("MonValue", iValue.getMonValue());
						obj.put("Units", iValue.getUnits());
						obj.put("Mark", iValue.getMark());
						obj.put("PollutantCode", myCode);
						objv.add(obj);
						
						// 单位转换
						transobj = new JSONObject();
						double tv = iValue.getMonValue();
						if (myCode.equals("a02006") // PM2.5
								|| myCode.equals("a02007") // SO2
								|| myCode.equals("a02009") // NO
								|| myCode.equals("a02010") // NOx
								|| myCode.equals("a02011") // NO2
								|| myCode.equals("a02012") // O3
								|| myCode.equals("a02013") // PM10
								) {
							tv *= 1000;
						}
						
						transobj.put("MonValue", tv);
						transobj.put("Units", iValue.getUnits());
						transobj.put("Mark", iValue.getMark());
						transobj.put("PollutantCode", myCode);
						transv.add(transobj);
					}
					data.put("pollutant", objv);
					trans.put("pollutant", transv);

					// 保存原始数据
					iprotocol = new AirFactor(data, mongodb);
					iprotocol.saveData();
					
					// 保存转换单位后数据
					AirFactor airFactor = new AirFactor(trans, mongodb);
					airFactor.saveTransData();
					
					log.info("大气六因子保存成功");
				}
				// 实时值不需要返回？
				if (valueType != ValueType.V30Second) {
					header = String.format(header + "@@@" + sdf.format(new Date()) + "tek");
					ctx.writeAndFlush(encode(header));
				}
			}
		} catch (Exception e) {
			log.info(e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * 将字符串转换为字节
	 * @param content
	 * @return
	 */
	public byte[] encode(String content) {
		byte[] result = null;
		byte[] bytes = content.getBytes();
		byte value = encheck(bytes, 0, bytes.length);
		String s = bytesToHexString(value);
		byte[] bytes2 = (s.length() == 1 ? "0" + s : s).getBytes();
		byte[] bytes3 = "####".getBytes();
		result = new byte[bytes.length + bytes2.length + bytes3.length];
		System.arraycopy(bytes, 0, result, 0, bytes.length);
		System.arraycopy(bytes2, 0, result, bytes.length, bytes2.length);
		System.arraycopy(bytes3, 0, result, bytes.length + bytes2.length, bytes3.length);

		return result;
	}

	public String bytesToHexString(byte src) {
		StringBuilder stringBuilder = new StringBuilder("");
		int v = src & 0xFF;
		String hv = Integer.toHexString(v);
		if (hv.length() < 2) {
			stringBuilder.append(0);
		}
		stringBuilder.append(hv);
		return stringBuilder.toString();
	}

	private byte encheck(byte[] buffer, int index, int length) {
		byte b = 0;
		for (int i = 0; i < length; i++) {
			b ^= buffer[index + i];
		}
		return b;
	}

	/**
	 * 将字符串转换为需要的数据格式
	 * @param body 消息字符串
	 * @param type 数据类型
	 * @return
	 */
	public List<IValue> decode(String body, ValueType type) {
		List<IValue> list = new ArrayList<IValue>();
		try {
			int num = body.indexOf("@@@");
			num -= 23;
			
			Date timePoint = sdf.parse(body.substring(num, num + 19));
			
			String stationCode = body.substring(4, num);
			num += 26;
			String[] pollutants = body.substring(num, body.length() - 6).split(";");
			
			for (int i = 0; i < pollutants.length; i++) {
				String pollutant = pollutants[i];
				String[] array3 = pollutant.split(",");
				double monValue = Double.parseDouble(array3[1]);

				String mark = "";
				if (array3.length == 3) {
					mark = array3[2];
				} else if (array3.length > 3) {
					for (int j = 2; j < array3.length; j++) {
						if (array3[j] != "") {
							mark += array3[j] + ",";
						}
					}
					mark = mark.substring(0, mark.length() - 1);
				}
				list.add(new AirBaseSrc_Ety(stationCode, timePoint, array3[0], monValue, mark, null, type));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return list;
	}

	private ValueType convertHeader(String value) {
		switch (value) {
		case "SYNC": // "同步信号"
			return ValueType.Synchronize;
		case "bn01": // "实时值"
			return ValueType.V30Second;
		case "JZ02": // "5分钟值"
			return ValueType.V5Minute;
		case "JZ05": // "小时值"
			return ValueType.V1Hour;
		case "JZ12": // "5分钟值"
			return ValueType.V5Minute;
		case "JZ16": // "小时值"
			return ValueType.V1Hour;
		case "JZ18": // "日均值(AQI)"
			return ValueType.V1Day_AQI;
		case "JZ06": // "日均值(API)"
			return ValueType.V1Day_API;
		case "ZD08": // "质控报表"
			return ValueType.QC;
		case "GDHB": // "质控命令"
			return ValueType.QCCommand;
		case "JZ08": // "质控报表"
			return ValueType.QC;
		case "JZ09": // "任务列表"
			return ValueType.QCTaskList;
		}
		return ValueType.Unknown;
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}
}
